1 module directx.d2d1_1helper;
2 /*=========================================================================*\
3 
4     Copyright (c) Microsoft Corporation.  All rights reserved.
5 
6     File: D2D1_1Helper.h
7 
8     Module Name: D2D
9 
10     Description: Helper files over the D2D interfaces and APIs.
11 
12 \*=========================================================================*/
13 
14 version(Windows):
15 
16 version(Direct2D_1_3)
17     version = Direct2D_1_2;
18 version(Direct2D_1_2)
19     version = Direct2D_1_1;
20 version(Direct2D_1_1):
21     version = Direct2D_1_0;
22 
23 version(DirectWrite):
24 version(WinCodec):
25 version(Direct2D_1_1):
26 
27 
28 public import directx.d2d1_1;
29 import directx.d2d1helper;
30 
31 template TypeTraits(T : INT32)
32 {
33     alias Point =  D2D1_POINT_2L;
34     alias Rect = D2D1_RECT_L;
35 }
36 
37 template TypeTraits(T : LONG)
38 {
39     alias Point = D2D1_POINT_2L;
40     alias Rect = D2D1_RECT_L;
41 }
42 
43 struct Matrix4x3F // : D2D1_MATRIX_4X3_F
44 {
45     D2D1_MATRIX_4X3_F matrix;
46     alias matrix this;
47 
48     nothrow this(D2D1_MATRIX_4X3_F m) { matrix = m; }
49     nothrow this(
50         FLOAT m11, FLOAT m12, FLOAT m13,
51         FLOAT m21, FLOAT m22, FLOAT m23,
52         FLOAT m31, FLOAT m32, FLOAT m33,
53         FLOAT m41, FLOAT m42, FLOAT m43
54         )
55     {
56         _11 = m11;
57         _12 = m12;
58         _13 = m13;
59 
60         _21 = m21;
61         _22 = m22;
62         _23 = m23;
63 
64         _31 = m31;
65         _32 = m32;
66         _33 = m33;
67 
68         _41 = m41;
69         _42 = m42;
70         _43 = m43;
71     }
72 
73     // this()
74     /// Use this instead of default constructor
75     static @property nothrow Identity()
76     {
77         return Matrix4x3F(
78             1, 0, 0,
79             0, 1, 0,
80             0, 0, 1,
81             0, 0, 0
82         );
83     }
84 }
85 
86 struct Matrix4x4F // : public D2D1_MATRIX_4X4_F
87 {
88     D2D1_MATRIX_4X4_F matrix;
89     alias matrix this;
90 
91     nothrow this(D2D1_MATRIX_4X4_F m) { matrix = m; }
92     nothrow this(
93         FLOAT m11, FLOAT m12, FLOAT m13, FLOAT m14,
94         FLOAT m21, FLOAT m22, FLOAT m23, FLOAT m24,
95         FLOAT m31, FLOAT m32, FLOAT m33, FLOAT m34,
96         FLOAT m41, FLOAT m42, FLOAT m43, FLOAT m44
97         )
98     {
99         _11 = m11;
100         _12 = m12;
101         _13 = m13;
102         _14 = m14;
103 
104         _21 = m21;
105         _22 = m22;
106         _23 = m23;
107         _24 = m24;
108 
109         _31 = m31;
110         _32 = m32;
111         _33 = m33;
112         _34 = m34;
113 
114         _41 = m41;
115         _42 = m42;
116         _43 = m43;
117         _44 = m44;
118     }
119 
120     // this()
121     /// Use this instead of default constructor
122     static nothrow @property Identity()
123     {
124         return Matrix4x4F(
125             1, 0, 0, 0,
126             0, 1, 0, 0,
127             0, 0, 1, 0,
128             0, 0, 0, 1
129         );
130     }
131 
132     bool opEquals(
133         const Matrix4x4F r
134         ) const
135     {
136         return _11 == r._11 && _12 == r._12 && _13 == r._13 && _14 == r._14 &&
137                 _21 == r._21 && _22 == r._22 && _23 == r._23 && _24 == r._24 &&
138                 _31 == r._31 && _32 == r._32 && _33 == r._33 && _34 == r._34 &&
139                 _41 == r._41 && _42 == r._42 && _43 == r._43 && _44 == r._44;
140     }
141 
142     static
143     Matrix4x4F
144     Translation(FLOAT x, FLOAT y, FLOAT z)
145     {
146         Matrix4x4F translation;
147 
148         translation._11 = 1.0; translation._12 = 0.0; translation._13 = 0.0; translation._14 = 0.0;
149         translation._21 = 0.0; translation._22 = 1.0; translation._23 = 0.0; translation._24 = 0.0;
150         translation._31 = 0.0; translation._32 = 0.0; translation._33 = 1.0; translation._34 = 0.0;
151         translation._41 = x;   translation._42 = y;   translation._43 = z;   translation._44 = 1.0;
152 
153         return translation;
154     }
155 
156     static
157     Matrix4x4F
158     Scale(FLOAT x, FLOAT y, FLOAT z)
159     {
160         Matrix4x4F scale;
161 
162         scale._11 = x;   scale._12 = 0.0; scale._13 = 0.0; scale._14 = 0.0;
163         scale._21 = 0.0; scale._22 = y;   scale._23 = 0.0; scale._24 = 0.0;
164         scale._31 = 0.0; scale._32 = 0.0; scale._33 = z;   scale._34 = 0.0;
165         scale._41 = 0.0; scale._42 = 0.0; scale._43 = 0.0; scale._44 = 1.0;
166 
167         return scale;
168     }
169 
170     static
171     Matrix4x4F
172     RotationX(FLOAT degreeX)
173     {
174         FLOAT angleInRadian = degreeX * (3.141592654f / 180.0f);
175 
176         FLOAT sinAngle = 0.0;
177         FLOAT cosAngle = 0.0;
178         D2D1SinCos(angleInRadian, &sinAngle, &cosAngle);
179 
180         return Matrix4x4F(
181             1, 0,         0,        0,
182             0, cosAngle,  sinAngle, 0,
183             0, -sinAngle, cosAngle, 0,
184             0, 0,         0,        1
185             );
186     }
187 
188     static
189     Matrix4x4F
190     RotationY(FLOAT degreeY)
191     {
192         FLOAT angleInRadian = degreeY * (3.141592654f / 180.0f);
193 
194         FLOAT sinAngle = 0.0;
195         FLOAT cosAngle = 0.0;
196         D2D1SinCos(angleInRadian, &sinAngle, &cosAngle);
197 
198         return Matrix4x4F(
199             cosAngle, 0, -sinAngle, 0,
200             0,        1, 0,         0,
201             sinAngle, 0, cosAngle,  0,
202             0,        0, 0,         1
203             );
204     }
205 
206     static
207     Matrix4x4F
208     RotationZ(FLOAT degreeZ)
209     {
210         FLOAT angleInRadian = degreeZ * (3.141592654f / 180.0f);
211 
212         FLOAT sinAngle = 0.0;
213         FLOAT cosAngle = 0.0;
214         D2D1SinCos(angleInRadian, &sinAngle, &cosAngle);
215 
216         return Matrix4x4F(
217             cosAngle,  sinAngle, 0, 0,
218             -sinAngle, cosAngle, 0, 0,
219             0,         0,        1, 0,
220             0,         0,        0, 1
221             );
222     }
223 
224     //
225     // 3D Rotation matrix for an arbitrary axis specified by x, y and z
226     //
227     static
228     Matrix4x4F
229     RotationArbitraryAxis(FLOAT x, FLOAT y, FLOAT z, FLOAT degree)
230     {
231         // Normalize the vector represented by x, y, and z
232         FLOAT magnitude = D2D1Vec3Length(x, y, z);
233         x /= magnitude;
234         y /= magnitude;
235         z /= magnitude;
236 
237         FLOAT angleInRadian = degree * (3.141592654f / 180.0f);
238 
239         FLOAT sinAngle = 0.0;
240         FLOAT cosAngle = 0.0;
241         D2D1SinCos(angleInRadian, &sinAngle, &cosAngle);
242 
243         FLOAT oneMinusCosAngle = 1 - cosAngle;
244 
245         return Matrix4x4F(
246             1             + oneMinusCosAngle * (x * x - 1),
247             z  * sinAngle + oneMinusCosAngle *  x * y,
248             -y * sinAngle + oneMinusCosAngle *  x * z,
249             0,
250 
251             -z * sinAngle + oneMinusCosAngle *  y * x,
252             1             + oneMinusCosAngle * (y * y - 1),
253             x  * sinAngle + oneMinusCosAngle *  y * z,
254             0,
255 
256             y  * sinAngle + oneMinusCosAngle *  z * x,
257             -x * sinAngle + oneMinusCosAngle *  z * y,
258             1             + oneMinusCosAngle * (z * z - 1) ,
259             0,
260 
261             0, 0, 0, 1
262             );
263     }
264 
265     static
266     Matrix4x4F
267     SkewX(FLOAT degreeX)
268     {
269         FLOAT angleInRadian = degreeX * (3.141592654f / 180.0f);
270 
271         FLOAT tanAngle = D2D1Tan(angleInRadian);
272 
273         return Matrix4x4F(
274             1,          0,  0, 0,
275             tanAngle,   1,  0, 0,
276             0,          0,  1, 0,
277             0,          0,  0, 1
278             );
279     }
280 
281     static
282     Matrix4x4F
283     SkewY(FLOAT degreeY)
284     {
285         FLOAT angleInRadian = degreeY * (3.141592654f / 180.0f);
286 
287         FLOAT tanAngle = D2D1Tan(angleInRadian);
288 
289         return Matrix4x4F(
290             1,  tanAngle,   0, 0,
291             0,  1,          0, 0,
292             0,  0,          1, 0,
293             0,  0,          0, 1
294             );
295     }
296 
297 
298     static
299     Matrix4x4F
300     PerspectiveProjection(FLOAT depth)
301     {
302         float proj = 0;
303 
304         if (depth > 0)
305         {
306             proj = -1/depth;
307         }
308 
309         return Matrix4x4F(
310             1, 0, 0, 0,
311             0, 1, 0, 0,
312             0, 0, 1, proj,
313             0, 0, 0, 1
314             );
315     }
316 
317     //
318     // Functions for convertion from the base D2D1_MATRIX_4X4_f to
319     // this type without making a copy
320     //
321     static
322     const(Matrix4x4F)*
323     ReinterpretBaseType(const(D2D1_MATRIX_4X4_F)* pMatrix)
324     {
325         return cast(const(Matrix4x4F)*)pMatrix;
326     }
327 
328     static
329     nothrow
330     Matrix4x4F*
331     ReinterpretBaseType(D2D1_MATRIX_4X4_F *pMatrix)
332     {
333         return cast(Matrix4x4F*)(pMatrix);
334     }
335 
336     nothrow
337     FLOAT
338     Determinant() const
339     {
340         FLOAT minor1 = _41 * (_12 * (_23 * _34 - _33 * _24) - _13 * (_22 * _34 - _24 * _32) + _14 * (_22 * _33 - _23 * _32));
341         FLOAT minor2 = _42 * (_11 * (_21 * _34 - _31 * _24) - _13 * (_21 * _34 - _24 * _31) + _14 * (_21 * _33 - _23 * _31));
342         FLOAT minor3 = _43 * (_11 * (_22 * _34 - _32 * _24) - _12 * (_21 * _34 - _24 * _31) + _14 * (_21 * _32 - _22 * _31));
343         FLOAT minor4 = _44 * (_11 * (_22 * _33 - _32 * _23) - _12 * (_21 * _33 - _23 * _31) + _13 * (_21 * _32 - _22 * _31));
344 
345         return minor1 - minor2 + minor3 - minor4;
346     }
347 
348     nothrow
349     bool
350     IsIdentity() const
351     {
352         return _11 == 1.0f && _12 == 0.0f && _13 == 0.0f && _14 == 0.0f
353             && _21 == 0.0f && _22 == 1.0f && _23 == 0.0f && _24 == 0.0f
354             && _31 == 0.0f && _32 == 0.0f && _33 == 1.0f && _34 == 0.0f
355             && _41 == 0.0f && _42 == 0.0f && _43 == 0.0f && _44 == 1.0f;
356     }
357 
358     nothrow
359     void
360     SetProduct(const Matrix4x4F a, const Matrix4x4F b)
361     {
362         _11 = a._11 * b._11 + a._12 * b._21 + a._13 * b._31 + a._14 * b._41;
363         _12 = a._11 * b._12 + a._12 * b._22 + a._13 * b._32 + a._14 * b._42;
364         _13 = a._11 * b._13 + a._12 * b._23 + a._13 * b._33 + a._14 * b._43;
365         _14 = a._11 * b._14 + a._12 * b._24 + a._13 * b._34 + a._14 * b._44;
366 
367         _21 = a._21 * b._11 + a._22 * b._21 + a._23 * b._31 + a._24 * b._41;
368         _22 = a._21 * b._12 + a._22 * b._22 + a._23 * b._32 + a._24 * b._42;
369         _23 = a._21 * b._13 + a._22 * b._23 + a._23 * b._33 + a._24 * b._43;
370         _24 = a._21 * b._14 + a._22 * b._24 + a._23 * b._34 + a._24 * b._44;
371 
372         _31 = a._31 * b._11 + a._32 * b._21 + a._33 * b._31 + a._34 * b._41;
373         _32 = a._31 * b._12 + a._32 * b._22 + a._33 * b._32 + a._34 * b._42;
374         _33 = a._31 * b._13 + a._32 * b._23 + a._33 * b._33 + a._34 * b._43;
375         _34 = a._31 * b._14 + a._32 * b._24 + a._33 * b._34 + a._34 * b._44;
376 
377         _41 = a._41 * b._11 + a._42 * b._21 + a._43 * b._31 + a._44 * b._41;
378         _42 = a._41 * b._12 + a._42 * b._22 + a._43 * b._32 + a._44 * b._42;
379         _43 = a._41 * b._13 + a._42 * b._23 + a._43 * b._33 + a._44 * b._43;
380         _44 = a._41 * b._14 + a._42 * b._24 + a._43 * b._34 + a._44 * b._44;
381     }
382 
383     nothrow
384     Matrix4x4F
385     opBinary(string op)(const Matrix4x4F matrix) const if(op == "*")
386     {
387         Matrix4x4F result;
388 
389         result.SetProduct(*this, matrix);
390 
391         return result;
392     }
393 }
394 
395 
396 struct Matrix5x4F // : D2D1_MATRIX_5X4_F
397 {
398     D2D1_MATRIX_5X4_F matrix;
399     alias matrix this;
400 
401     nothrow this(D2D1_MATRIX_5X4_F m) { matrix = m; }
402     nothrow this(
403         FLOAT m11, FLOAT m12, FLOAT m13, FLOAT m14,
404         FLOAT m21, FLOAT m22, FLOAT m23, FLOAT m24,
405         FLOAT m31, FLOAT m32, FLOAT m33, FLOAT m34,
406         FLOAT m41, FLOAT m42, FLOAT m43, FLOAT m44,
407         FLOAT m51, FLOAT m52, FLOAT m53, FLOAT m54
408         )
409     {
410         _11 = m11;
411         _12 = m12;
412         _13 = m13;
413         _14 = m14;
414 
415         _21 = m21;
416         _22 = m22;
417         _23 = m23;
418         _24 = m24;
419 
420         _31 = m31;
421         _32 = m32;
422         _33 = m33;
423         _34 = m34;
424 
425         _41 = m41;
426         _42 = m42;
427         _43 = m43;
428         _44 = m44;
429 
430         _51 = m51;
431         _52 = m52;
432         _53 = m53;
433         _54 = m54;
434     }
435 
436     // this()
437     /// Use this instead of default constructor
438     static nothrow @property Identity()
439     {
440         return Matrix5x4F(
441             1, 0, 0, 0,
442             0, 1, 0, 0,
443             0, 0, 1, 0,
444             0, 0, 0, 1,
445             0, 0, 0, 0
446         );
447     }
448 }
449 
450 D2D1_COLOR_F
451 ConvertColorSpace(
452     D2D1_COLOR_SPACE sourceColorSpace,
453     D2D1_COLOR_SPACE destinationColorSpace,
454     const D2D1_COLOR_F color
455     )
456 {
457     return D2D1ConvertColorSpace(
458         sourceColorSpace,
459         destinationColorSpace,
460         &color
461         );
462 }
463 
464 D2D1_DRAWING_STATE_DESCRIPTION1
465 DrawingStateDescription1(
466     D2D1_ANTIALIAS_MODE antialiasMode = D2D1_ANTIALIAS_MODE_PER_PRIMITIVE,
467     D2D1_TEXT_ANTIALIAS_MODE textAntialiasMode = D2D1_TEXT_ANTIALIAS_MODE_DEFAULT,
468     D2D1_TAG tag1 = 0,
469     D2D1_TAG tag2 = 0,
470     const D2D1_MATRIX_3X2_F transform = D2D1.IdentityMatrix(),
471     D2D1_PRIMITIVE_BLEND primitiveBlend = D2D1_PRIMITIVE_BLEND_SOURCE_OVER,
472     D2D1_UNIT_MODE unitMode = D2D1_UNIT_MODE_DIPS
473     )
474 {
475     D2D1_DRAWING_STATE_DESCRIPTION1 drawingStateDescription1;
476 
477     drawingStateDescription1.antialiasMode = antialiasMode;
478     drawingStateDescription1.textAntialiasMode = textAntialiasMode;
479     drawingStateDescription1.tag1 = tag1;
480     drawingStateDescription1.tag2 = tag2;
481     drawingStateDescription1.transform = transform;
482     drawingStateDescription1.primitiveBlend = primitiveBlend;
483     drawingStateDescription1.unitMode = unitMode;
484 
485     return drawingStateDescription1;
486 }
487 
488 D2D1_DRAWING_STATE_DESCRIPTION1
489 DrawingStateDescription1(
490     const D2D1_DRAWING_STATE_DESCRIPTION desc,
491     D2D1_PRIMITIVE_BLEND primitiveBlend = D2D1_PRIMITIVE_BLEND_SOURCE_OVER,
492     D2D1_UNIT_MODE unitMode = D2D1_UNIT_MODE_DIPS
493     )
494 {
495     D2D1_DRAWING_STATE_DESCRIPTION1 drawingStateDescription1;
496 
497     drawingStateDescription1.antialiasMode = desc.antialiasMode;
498     drawingStateDescription1.textAntialiasMode = desc.textAntialiasMode;
499     drawingStateDescription1.tag1 = desc.tag1;
500     drawingStateDescription1.tag2 = desc.tag2;
501     drawingStateDescription1.transform = desc.transform;
502     drawingStateDescription1.primitiveBlend = primitiveBlend;
503     drawingStateDescription1.unitMode = unitMode;
504 
505     return drawingStateDescription1;
506 }
507 
508 D2D1_BITMAP_PROPERTIES1
509 BitmapProperties1(
510     D2D1_BITMAP_OPTIONS bitmapOptions = D2D1_BITMAP_OPTIONS_NONE,
511     const D2D1_PIXEL_FORMAT pixelFormat = D2D1.PixelFormat(),
512     FLOAT dpiX = 96.0f,
513     FLOAT dpiY = 96.0f,
514     ID2D1ColorContext colorContext = null
515     )
516 {
517     D2D1_BITMAP_PROPERTIES1 bitmapProperties =
518     {
519         pixelFormat,
520         dpiX, dpiY,
521         bitmapOptions,
522         colorContext
523     };
524 
525     return bitmapProperties;
526 }    
527 
528 D2D1_LAYER_PARAMETERS1
529 LayerParameters1(
530     const D2D1_RECT_F contentBounds = D2D1.InfiniteRect(),
531     ID2D1Geometry geometricMask = NULL,
532     D2D1_ANTIALIAS_MODE maskAntialiasMode = D2D1_ANTIALIAS_MODE_PER_PRIMITIVE,
533     D2D1_MATRIX_3X2_F maskTransform = D2D1.IdentityMatrix(),
534     FLOAT opacity = 1.0,
535     ID2D1Brush opacityBrush = NULL,
536     D2D1_LAYER_OPTIONS1 layerOptions = D2D1_LAYER_OPTIONS1_NONE
537     )
538 {
539     D2D1_LAYER_PARAMETERS1 layerParameters;
540 
541     layerParameters.contentBounds = contentBounds;
542     layerParameters.geometricMask = geometricMask;
543     layerParameters.maskAntialiasMode = maskAntialiasMode;
544     layerParameters.maskTransform = maskTransform;
545     layerParameters.opacity = opacity;
546     layerParameters.opacityBrush = opacityBrush;
547     layerParameters.layerOptions = layerOptions;
548 
549     return layerParameters;
550 }
551 
552 D2D1_STROKE_STYLE_PROPERTIES1
553 StrokeStyleProperties1(
554     D2D1_CAP_STYLE startCap = D2D1_CAP_STYLE_FLAT,
555     D2D1_CAP_STYLE endCap = D2D1_CAP_STYLE_FLAT,
556     D2D1_CAP_STYLE dashCap = D2D1_CAP_STYLE_FLAT,
557     D2D1_LINE_JOIN lineJoin = D2D1_LINE_JOIN_MITER,
558     FLOAT miterLimit = 10.0f,
559     D2D1_DASH_STYLE dashStyle = D2D1_DASH_STYLE_SOLID,
560     FLOAT dashOffset = 0.0f,
561     D2D1_STROKE_TRANSFORM_TYPE transformType = D2D1_STROKE_TRANSFORM_TYPE_NORMAL
562     )
563 {
564     D2D1_STROKE_STYLE_PROPERTIES1 strokeStyleProperties;
565 
566     strokeStyleProperties.startCap = startCap;
567     strokeStyleProperties.endCap = endCap;
568     strokeStyleProperties.dashCap = dashCap;
569     strokeStyleProperties.lineJoin = lineJoin;
570     strokeStyleProperties.miterLimit = miterLimit;
571     strokeStyleProperties.dashStyle = dashStyle;
572     strokeStyleProperties.dashOffset = dashOffset;
573     strokeStyleProperties.transformType = transformType;
574 
575     return strokeStyleProperties;
576 }
577 
578 D2D1_IMAGE_BRUSH_PROPERTIES
579 ImageBrushProperties(
580     D2D1_RECT_F sourceRectangle,
581     D2D1_EXTEND_MODE extendModeX = D2D1_EXTEND_MODE_CLAMP,
582     D2D1_EXTEND_MODE extendModeY = D2D1_EXTEND_MODE_CLAMP,
583     D2D1_INTERPOLATION_MODE interpolationMode = D2D1_INTERPOLATION_MODE_LINEAR
584     )
585 {
586     D2D1_IMAGE_BRUSH_PROPERTIES imageBrushProperties;
587 
588     imageBrushProperties.extendModeX = extendModeX;
589     imageBrushProperties.extendModeY = extendModeY;
590     imageBrushProperties.interpolationMode = interpolationMode;
591     imageBrushProperties.sourceRectangle = sourceRectangle;
592 
593     return imageBrushProperties;
594 }
595 
596 D2D1_BITMAP_BRUSH_PROPERTIES1
597 BitmapBrushProperties1(
598     D2D1_EXTEND_MODE extendModeX = D2D1_EXTEND_MODE_CLAMP,
599     D2D1_EXTEND_MODE extendModeY = D2D1_EXTEND_MODE_CLAMP,
600     D2D1_INTERPOLATION_MODE interpolationMode = D2D1_INTERPOLATION_MODE_LINEAR
601     )
602 {
603     D2D1_BITMAP_BRUSH_PROPERTIES1 bitmapBrush1Properties;
604 
605     bitmapBrush1Properties.extendModeX = extendModeX;
606     bitmapBrush1Properties.extendModeY = extendModeY;
607     bitmapBrush1Properties.interpolationMode = interpolationMode;
608 
609     return bitmapBrush1Properties;
610 }
611 
612 D2D1_PRINT_CONTROL_PROPERTIES
613 PrintControlProperties(
614     D2D1_PRINT_FONT_SUBSET_MODE fontSubsetMode = D2D1_PRINT_FONT_SUBSET_MODE_DEFAULT,
615     FLOAT rasterDpi = 150.0f,
616     D2D1_COLOR_SPACE colorSpace = D2D1_COLOR_SPACE_SRGB
617     )
618 {
619     D2D1_PRINT_CONTROL_PROPERTIES printControlProps;
620 
621     printControlProps.fontSubset = fontSubsetMode;
622     printControlProps.rasterDPI = rasterDpi;
623     printControlProps.colorSpace = colorSpace;
624 
625     return printControlProps;
626 }
627 
628 D2D1_RENDERING_CONTROLS
629 RenderingControls(
630     D2D1_BUFFER_PRECISION bufferPrecision,
631     D2D1_SIZE_U tileSize
632     )
633 {
634     D2D1_RENDERING_CONTROLS renderingControls;
635 
636     renderingControls.bufferPrecision = bufferPrecision;
637     renderingControls.tileSize = tileSize;
638 
639     return renderingControls;
640 }
641 
642 D2D1_EFFECT_INPUT_DESCRIPTION
643 EffectInputDescription(
644     ID2D1Effect effect,
645     UINT32 inputIndex,
646     D2D1_RECT_F inputRectangle
647     )
648 {
649     D2D1_EFFECT_INPUT_DESCRIPTION description;
650 
651     description.effect = effect;
652     description.inputIndex = inputIndex;
653     description.inputRectangle = inputRectangle;
654 
655     return description;
656 }
657 
658 D2D1_CREATION_PROPERTIES
659 CreationProperties(
660     D2D1_THREADING_MODE threadingMode,
661     D2D1_DEBUG_LEVEL debugLevel,
662     D2D1_DEVICE_CONTEXT_OPTIONS options
663     )
664 {
665     D2D1_CREATION_PROPERTIES creationProperties;
666 
667     creationProperties.threadingMode = threadingMode;
668     creationProperties.debugLevel = debugLevel;
669     creationProperties.options = options;
670 
671     return creationProperties;
672 }
673 
674 D2D1_VECTOR_2F
675 Vector2F(
676     FLOAT x = 0.0f,
677     FLOAT y = 0.0f
678     )
679 {
680     D2D1_VECTOR_2F vec2 = {x, y};
681     return vec2;
682 }
683 
684 D2D1_VECTOR_3F
685 Vector3F(
686     FLOAT x = 0.0f,
687     FLOAT y = 0.0f,
688     FLOAT z = 0.0f
689     )
690 {
691     D2D1_VECTOR_3F vec3 = {x, y, z};
692     return vec3;
693 }
694 
695 D2D1_VECTOR_4F
696 Vector4F(
697     FLOAT x = 0.0f,
698     FLOAT y = 0.0f,
699     FLOAT z = 0.0f,
700     FLOAT w = 0.0f
701     )
702 {
703     D2D1_VECTOR_4F vec4 = {x, y, z, w};
704     return vec4;
705 }
706 
707 D2D1_POINT_2L
708 Point2L(
709     INT32 x = 0,
710     INT32 y = 0
711     )
712 {
713     return D2D1_POINT_2L(x, y);
714 }
715 
716 D2D1_RECT_L
717 RectL(
718     INT32 left = 0,
719     INT32 top = 0,
720     INT32 right = 0,
721     INT32 bottom = 0
722     )
723 {
724     return D2D1_RECT_L(left, top, right, bottom);
725 }
726 
727 ///
728 /// Sets a bitmap as an effect input, while inserting a DPI compensation effect
729 /// to preserve visual appearance as the device context's DPI changes.
730 /// 
731 HRESULT
732 SetDpiCompensatedEffectInput(
733     ID2D1DeviceContext deviceContext,
734     ID2D1Effect effect,
735     UINT32 inputIndex,
736     ID2D1Bitmap inputBitmap,
737     D2D1_INTERPOLATION_MODE interpolationMode = D2D1_INTERPOLATION_MODE_LINEAR,
738     D2D1_BORDER_MODE borderMode = D2D1_BORDER_MODE_HARD
739     )
740 {
741     HRESULT hr = S_OK;
742     ID2D1Effect dpiCompensationEffect = null;
743 
744     if (inputBitmap is null)
745     {
746         effect.SetInput(inputIndex, null);
747         return hr;
748     }
749 
750     hr = deviceContext.CreateEffect(&CLSID_D2D1DpiCompensation, &dpiCompensationEffect);
751 
752     if (SUCCEEDED(hr))
753     {
754             if (SUCCEEDED(hr))
755             {
756                 dpiCompensationEffect.SetInput(0, inputBitmap);
757 
758                 D2D1_POINT_2F bitmapDpi;
759                 inputBitmap.GetDpi(bitmapDpi.x, bitmapDpi.y);
760                 hr = dpiCompensationEffect.SetValue(D2D1_DPICOMPENSATION_PROP_INPUT_DPI, bitmapDpi);
761             }
762 
763             if (SUCCEEDED(hr))
764             {
765                 hr = dpiCompensationEffect.SetValue(D2D1_DPICOMPENSATION_PROP_INTERPOLATION_MODE, interpolationMode);
766             }
767 
768             if (SUCCEEDED(hr))
769             {
770                 hr = dpiCompensationEffect.SetValue(D2D1_DPICOMPENSATION_PROP_BORDER_MODE, borderMode);
771             }
772 
773             if (SUCCEEDED(hr))
774             {
775                 effect.SetInputEffect(inputIndex, dpiCompensationEffect);
776             }
777 
778             if (dpiCompensationEffect !is null)
779             {
780                 dpiCompensationEffect.Release();
781             }
782     }
783 
784     return hr;
785 }